package org.benjamin.lending.service.impl;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.benjamin.lending.domain.entity.*;
import org.benjamin.lending.form.TenderLogIndex;
import org.benjamin.lending.repository.*;
import org.benjamin.lending.service.BorrowService;
import org.benjamin.lending.trusteeship.sumapay.BorrowReportOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.io.*;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

/**
 * 
 * @author 黄文杰
 *
 */
@Transactional
@Service("borrowService")
public class BorrowServiceImpl implements BorrowService{

    private final Logger logger = LogManager.getLogger();

    @Autowired
    private MemberInfoRepository memberInfoRepository;

    @Autowired
    private BorrowTenderRepository borrowTenderRepository;

    @Autowired
    private BorrowInfoRepository borrowInfoRepository;
    
    @Autowired
    private BorrowVerifyRepository borrowVerifyRepository;

    @Autowired
    private BorrowContractRepository borrowContractRepository;
    
    @Autowired
    private BorrowProductRepository borrowProductRepository;

    @Autowired
    private TemplateEngine templateEngine;
    
    @Autowired
    private BorrowReportOperation borrowReportOperation;

    @Override
    public boolean tenderCheck(MemberInfo memberInfo) {
        boolean pass = false;
        pass = memberInfo.getMemberStatus().isOpenAccount();
        return pass;
    }

    @Override
    public boolean tenderCheck(String username) {
        MemberInfo memberInfo = this.memberInfoRepository.findByUsername(username);
        return this.tenderCheck(memberInfo);
    }

    @Override
    public BorrowTender tenderSuccess(BorrowInfo borrowInfo, MemberInfo memberInfo, BigDecimal amount, boolean auto){
        logger.info("借款投资成功保存投资信息");
        BorrowTender borrowTender = new BorrowTender();
        borrowTender.setBorrowInfo(borrowInfo);
        borrowTender.setMemberInfo(memberInfo);
        borrowTender.setInvestorCapital(amount);
        borrowTender.setAuto(auto);
        borrowTender.setStatus(0);
        this.borrowTenderRepository.save(borrowTender);
        return borrowTender;
    }

    @Override
    public Page<BorrowInfo> findBorrowInfoList(PageRequest pageRequest) {
        return this.borrowInfoRepository.findAll(pageRequest);
    }

    @Override
    public Page<BorrowInfo> findBorrowInfoPage() {
        return this.borrowInfoRepository.findAll(new PageRequest(0,10));
    }
    
    

    @Override
	public List<BorrowProduct> findProductList() {
		return this.borrowProductRepository.findAll();
	}

	/**
     * 创建借款标
     */
    @Override
    public void createBorrowInfo(BorrowInfo borrowInfo) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyMMddHHss");
        borrowInfo.setNo(simpleDateFormat.format(System.currentTimeMillis()));
        borrowInfo.setCreateTime(new Timestamp(System.currentTimeMillis()));
        borrowInfo.setStatus(BorrowStatus.waiting);
        if(borrowInfo.getBusinessInfo() == null){
        	logger.info("当前借款标不对应任何业务信息");
        }else{
        	if(borrowInfo.getBusinessInfo().getBorrowId() == null){
        		borrowInfo.setBusinessInfo(null);
        	}else{
        		logger.info("当前借款表对应的业务信息编号：{}",borrowInfo.getBusinessInfo());	
        	}
        	
        }
        
        logger.info("开始计算管理费");
        BorrowProduct borrowProduct = borrowInfo.getBorrowProduct();
        Assert.notNull(borrowProduct,"借款标产品信息有误，无法计算借款管理费");
        BigDecimal managementExpense = borrowInfo.getTotalMoney().multiply(borrowProduct.getManagementFeeRatio());
        borrowInfo.setManagementExpense(managementExpense);
        this.borrowInfoRepository.save(borrowInfo);
    }

    @Override
    public BorrowInfo getBorrowById(Integer id) {
        return this.borrowInfoRepository.findOne(id);
    }

	@Override
	public void updateEntity(BorrowInfo borrowInfo) {
		if(borrowInfo.getBusinessInfo() == null || borrowInfo.getBusinessInfo().getBorrowId() == null){
			borrowInfo.setBusinessInfo(null);
		}
		this.borrowInfoRepository.save(borrowInfo);
	}
	
	@Override
	public void auding(String type,String message,boolean result,Integer borrowId,String username){
		BorrowInfo borrowInfo = this.borrowInfoRepository.findOne(borrowId);
		if(type.equals("waiting")){
			BorrowVerify borrowVerify = new BorrowVerify();
			borrowVerify.setBorrowId(borrowInfo.getId());
			borrowVerify.setDealInfo(message);
			borrowVerify.setDealStatus(result);
			borrowVerify.setDealUser(username);
			borrowVerify.setDealTime(new Timestamp(System.currentTimeMillis()));
			this.borrowVerifyRepository.save(borrowVerify);
			//审核通过后会将借款标项目在第三方报备
			if(result){
				this.borrowReportOperation.request(null, borrowId,null);	
			}
		}
		
	}

    @Override
    public Page<BorrowTender> findUserTenderLogPage(final TenderLogIndex tenderLogIndex) {
	    final MemberInfo memberInfo;
	    if(tenderLogIndex.getUserId() != null){
            memberInfo = this.memberInfoRepository.findOne(tenderLogIndex.getUserId());
        }else{
	        memberInfo = this.memberInfoRepository.findByUsername(tenderLogIndex.getUsername());
        }
        Specification<BorrowTender> specification = new Specification<BorrowTender>() {
            @Override
            public Predicate toPredicate(Root<BorrowTender> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                List<Predicate> predicateList = new ArrayList<>();
                predicateList.add(cb.equal(root.get("memberInfo").as(MemberInfo.class),memberInfo));
                if(tenderLogIndex.getStatus() != null){
                    predicateList.add(cb.equal(root.get("status"),tenderLogIndex.getStatus()));
                }
                Predicate[] predicates = new Predicate[predicateList.size()];
                return query.where(predicateList.toArray(predicates)).getGroupRestriction();
            }
        };
        return this.borrowTenderRepository.findAll(specification,tenderLogIndex.getPageRequest());
    }

    @Override
    public byte[] contractDemand(Integer borrowId,String username,boolean createBuilder) {
	    MemberInfo memberInfo = this.memberInfoRepository.findByUsername(username);
        BorrowContractIdentity identity = new BorrowContractIdentity();
        identity.setBorrowId(borrowId);
        identity.setUserId(memberInfo.getId());
	    BorrowContract borrowContract = this.borrowContractRepository.findOne(identity);
	    if(!createBuilder){
            if(borrowContract != null){
                logger.info("用户已经生成过合同直接从数据库读取");
                return borrowContract.getContent();
            }
        }
        try{
            borrowContract = this.createContract(borrowId,memberInfo);
            return borrowContract.getContent();
        }catch (Exception e){
	        logger.error(e.getMessage(),e);
        }
        return null;
    }

    public BorrowContract createContract(Integer borrowId,MemberInfo memberInfo) throws IOException, DocumentException {
        Context context = new Context();
        BorrowInfo borrowInfo = this.borrowInfoRepository.findOne(borrowId);
        context.setVariable("borrowInfo",borrowInfo);
	    String stringTemplate = this.templateEngine.process("borrowContract.html",context);
	    logger.info(stringTemplate);
	    byte[] content = this.createPDF(stringTemplate);

	    BorrowContractIdentity identity = new BorrowContractIdentity();

	    identity.setUserId(memberInfo.getId());
	    identity.setBorrowId(borrowInfo.getId());
        BorrowContract borrowContract = new BorrowContract();
        borrowContract.setIdentity(identity);
        borrowContract.setContent(content);
        borrowContract.setCreateTime(new Timestamp(System.currentTimeMillis()));
        this.borrowContractRepository.save(borrowContract);
        return borrowContract;
    }

    public byte[] createPDF(String borrowContract) throws DocumentException, IOException {
        Document document = new Document();
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        PdfWriter pdfWriter = PdfWriter.getInstance(document,outputStream);
        document.open();
        Reader reader = new StringReader(borrowContract);
        XMLWorkerHelper.getInstance().parseXHtml(pdfWriter,document,reader);
        document.close();
        byte[] content = outputStream.toByteArray();
        return content;
    }

	@Override
	public void addProduct(BorrowProduct borrowProduct) {
		this.borrowProductRepository.save(borrowProduct);
	}
}
